import extnames from '../dependencies/extnames.mjs';
import dirs from '../dependencies/dirs.mjs';
import { KFile } from '../utils/files/KFile.mjs';
import { KFileUtils } from '../utils/files/KFileUtils.mjs';
import path from 'path';
import fs from 'fs';
import CopyPlugin from 'copy-webpack-plugin';
import htmlMinifier from 'html-minifier';
import webpack_entry from './entry.mjs';

export default function (args, config) {
    const dir = path.join(dirs.run_project, 'src', 'html');

    if (!fs.existsSync(dir)) { return; }// 配置目录不存在时，不需要配置。

    if (fs.readdirSync(dir).length === 0) { return; }// 配置目录为空时，不需要配置。

    if (!config.plugins) { config.plugins = []; }

    let entry = config.entry;
    if (!args.enable_entry) {// 没有开启entry解析到webpack配置，但是此处需要entry信息。
        const c = {};// 创建一个空对象让entry模块解析。
        webpack_entry(args, c);
        entry = c.entry;
    }

    config.plugins.push(
        new CopyPlugin({
            patterns: [
                {
                    from: dir,
                    to: path.join('html', '[path]', '[name]' + '[ext]'),
                    filter: (filePath) => {
                        const extname = path.extname(filePath).toLowerCase();
                        return extnames.html.includes(extname);
                    },
                    transform(content, filePath) {
                        content = html(args, entry, content.toString(), filePath);

                        if (args.mode !== 'production') { return content; }

                        // 生产环境启用压缩
                        return htmlMinifier.minify(content.toString(), {
                            collapseWhitespace: true,
                            removeComments: true,
                        });
                    },
                },
            ],
            options: {
                concurrency: 33,
            },
        })
    );
};

import { JSDOM } from 'jsdom';
const { DOMParser } = new JSDOM('').window;
const _extnames_ = [...extnames.js, ...extnames.ts];
import resolve_path from '../dependencies/resolve_path.mjs';
function html(args, entry, content, filePath) {
    const doc = new DOMParser().parseFromString(content, 'text/html');

    // 相对路径引用的脚本文件，校验该脚本文件是否存在。
    {
        const dir$entry = path.join(dirs.run_project, 'src', 'js');
        const dir$lib = path.join(dirs.run_project, 'src', 'lib');
        const entries = Object.values(entry).map(entry => new KFile(entry).path.current);
        doc.querySelectorAll('script').forEach((script) => {
            const src = script.getAttribute('src');
            const src$resolved = resolve_path(filePath, src);

            // 外链接不处理
            if (!src$resolved.resolved) { return; }

            let comment;
            const file$script = new KFile(src$resolved.path);
            if (KFileUtils.isSubDir(file$script.path.dir, dir$entry)) {// 脚本源码文件
                if (file$script.path.dir === dir$entry) {// 是入口脚本文件
                    const entry = KFileUtils.like(file$script, entries);
                    if (entry) {// 是配置生效的（没有被包含排除过滤掉）入口脚本文件
                        // 后缀名处理
                        /*
                        * 入口文件一定存在。
                        * 脚本文件引入，不应支持省略后缀的形式。
                        * 最终编译后的脚本文件后缀名都是.js。
                        * 综上，直接以字符串处理去除后缀名后补充.js后缀名即可。
                        */
                        if (src.endsWith('.js')) { return; }
                        const src_new = src.slice(0, -file$script.name.ext.length) + '.js';
                        console.log('[I] =>', `reset attribute src[${src_new}] to script[${script.outerHTML}] when parsing the file: ${filePath}.`);
                        script.setAttribute('src', src_new);
                        return;
                    } else {// 被过滤掉的入口脚本文件（可能是测试代码或就是书写错误），需要做注释处理。
                        comment = 'entry script has been excluded';
                        console.log('[W] =>', `this code[${script.outerHTML}] might be an error when parsing the file: ${filePath}.`, '=>', comment, '.');
                        // to comment
                    }
                } else {// 非入口脚本文件，模块代码不应该直接引入。
                    throw new Error(`module script[${script.outerHTML}] can not be used as an entry script when parsing the file: ${filePath}.`);
                }
            } else if (KFileUtils.isSubDir(file$script.path.dir, dir$lib)) {// 三方库脚本文件
                // 不做后缀名处理
                if (KFileUtils.existsByExts(file$script, _extnames_)) { return; }// 文件存在，直接返回。
                // 文件不存在，可能在依赖项目的lib包中，输出提示信息。
                console.log('[W] =>', `this code[${script.outerHTML}] might be an error when parsing the file: ${filePath}.`, '=>', 'lib script maybe in the other project.');
                return;
            } else {// 其它不符合约定路径的情况，输出提示信息。
                comment = 'scripts file should be in directory[/src/js]';
                console.log('[E] =>', `this code[${script.outerHTML}] might be an error when parsing the file: ${filePath}.`, '=>', comment, '.');
                // to comment
            }

            // comment
            {
                const ele_temp_wrapper = doc.createElement('div');
                ele_temp_wrapper.innerHTML = `<!-- ${comment} -->` + `<!-- ${script.outerHTML} -->`;
                const ele_comment = ele_temp_wrapper.childNodes[0];
                const ele_script_comment = ele_temp_wrapper.childNodes[1];
                script.parentNode.insertBefore(ele_comment, script);
                script.parentNode.replaceChild(ele_script_comment, script);
            }
        });
    }

    // type属性处理
    if (args.use_module_script === true) {
        // script标签添加type="module"
        doc.querySelectorAll('script').forEach((script) => {
            if (!script.hasAttribute('type') || script.getAttribute('type') !== 'module') {
                script.setAttribute('type', 'module');
            }
        });
    } else {
        // 去除script标签中的type="module"
        doc.querySelectorAll('script[type="module"]').forEach((script) => {
            script.removeAttribute('type');
        });
        // 修改script标签中的type="script"
        doc.querySelectorAll('script[type="script"]').forEach((script) => {
            script.setAttribute('type', 'text/javascript');
        });
    }

    return Buffer.from(doc.documentElement.outerHTML);
}
